/******************************************************************************/
/*  Class DS1820                                                              */
/*  PO: S. Maslyakov, rusoil.9@gmail.com                                      */
/*                                                                            */
/*  Revision:     1.1                                                         */
/*  Date:         2010/12/16 17:14:33                                         */
/******************************************************************************/


#include "data_types.h"
#include "Core\core.h"
#include "Lib\crc16.h"
#include "TNKernel\tn.h"
#include "Ds1820\ds1820.h"


// Event
static TN_EVENT ds1820_event;
static sint32_t err;
static uint32_t pattern;


//==============================================================================
// App: Init hw
//==============================================================================
void DS1820::Init_Ds1820() {
    PINSEL1_bit.P0_27 = 0;  // As gpio
    FIO0DIR_bit.P0_27 = 0;  // As input
    PINMODE1_bit.P0_27 = 2; // PULL_RES

    Init_rtos_part();
    INIT_US_TIMER();
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Init rtos part
//==============================================================================
void DS1820::Init_rtos_part() {
    // Create event
    ds1820_event.id_event = 0;
    tn_event_create(&ds1820_event,                            // Ptr to already existing TN_EVENT
                    TN_EVENT_ATTR_SINGLE|TN_EVENT_ATTR_CLR,   // Attribute event
                    0UL                                       // Pattern initial value
                  );
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Get ds1820 event
//==============================================================================
void * DS1820::Get_ds1820_event() {
    return &ds1820_event;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Write bit to DS1820
//==============================================================================
void DS1820::WriteBit(const uint32_t _bit) {
    PinLow();

    if (_bit == 0) {
        //DELAY_MIN_US(60);
        DELAY_BIG_US(50); // 70
        err = tn_event_wait(&ds1820_event,
                            DS1820_DELAY_EVENT,
                            TN_EVENT_WCOND_OR,
                            &pattern,
                            TN_MSEC_TO_TICK(20));

        PinHigh();
    }
    else {
        DELAY_MIN_US(5);  // 10
        PinHigh();

        //DELAY_MIN_US(60);
        DELAY_BIG_US(45); // 65
        err = tn_event_wait(&ds1820_event,
                            DS1820_DELAY_EVENT,
                            TN_EVENT_WCOND_OR,
                            &pattern,
                            TN_MSEC_TO_TICK(20));
    };

    DELAY_MIN_US(2);      // 2
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Read bit from DS1820
//==============================================================================
uint32_t DS1820::ReadBit() {
    PinLow();            // Start a read time slot
    DELAY_MIN_US(2);

    PinHigh();
    DELAY_MIN_US(3);

    const uint32_t data = GetPin();

    //DELAY_MIN_US(60);
    DELAY_BIG_US(40);
    err = tn_event_wait(&ds1820_event,
                        DS1820_DELAY_EVENT,
                        TN_EVENT_WCOND_OR,
                        &pattern,
                        TN_MSEC_TO_TICK(20));

    return data;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Master reset to DS1820, and check the result
//==============================================================================
bool_t DS1820::MasterReset() {

    PinLow();     // Set to low for 720us to reset slave device

    DELAY_BIG_US(480);  // 480 min
    err = tn_event_wait(&ds1820_event,
                        DS1820_DELAY_EVENT,
                        TN_EVENT_WCOND_OR,
                        &pattern,
                        TN_MSEC_TO_TICK(20));

    PinHigh();   // Release the 1-Wire Bus
    if (err != TERR_NO_ERR) {
        return FALSE_T;
    };

    //DELAY_MIN_US(65);
    DELAY_BIG_US(60);   // 60 - 240
    err = tn_event_wait(&ds1820_event,
                        DS1820_DELAY_EVENT,
                        TN_EVENT_WCOND_OR,
                        &pattern,
                        TN_MSEC_TO_TICK(20));

    if (err != TERR_NO_ERR) {
        return FALSE_T;
    };

    const bool_t value = (GetPin() == 0) ? TRUE_T : FALSE_T;

    DELAY_BIG_US(410);  // 480
    err = tn_event_wait(&ds1820_event,
                        DS1820_DELAY_EVENT,
                        TN_EVENT_WCOND_OR,
                        &pattern,
                        TN_MSEC_TO_TICK(20));

    if (err != TERR_NO_ERR) {
        return FALSE_T;
    };

    return value;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Write byte to DS1820
//==============================================================================
void DS1820::WriteByte(const uint8_t _data) {
    for (uint32_t i = 0; i < 8; i++) {
        WriteBit((_data & (1 << i)) ? 1 : 0);
    };
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Read byte from DS1820
//==============================================================================
uint8_t DS1820::ReadByte() {
    uint8_t data = 0;

    for (uint32_t i = 0; i < 8; i++) {
        data |= (ReadBit() == 1) ? (1 << i) : 0;
    };

    return data;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Multi Write byte to DS1820
//==============================================================================
void DS1820::MultiWriteByte(const uint8_t * _pData, const uint32_t _len) {
    if (!_len) {
        return;
    };

    for (uint32_t i = 0; i < _len; i++) {
        WriteByte(*_pData++);
    };
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Multi Read byte from DS1820
//==============================================================================
void DS1820::MultiReadByte(const uint32_t _len) {
    if ((!_len) || (_len > sizeof(m_buff))) {
        return;
    };

    for (uint32_t i = 0; i < _len; i++) {
        m_buff[i] = ReadByte();
    };
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Rom search
//==============================================================================
uint32_t DS1820::RomSearch(uint32_t _diff, uint8_t * _id) {
    uint32_t i;
    uint32_t j;
    uint32_t next_diff;
    uint32_t b;

    if (DS1820::MasterReset() == FALSE_T) {
        return eDS_PRESENCE_ERR;            // error, no device found
    };

    WriteByte(eDS_SEARCH_ROM);              // ROM search command
    next_diff = eDS_LAST_DEV;               // unchanged on last device

    i = DS1820_ROMCODE_SIZE * 8;            // 64 bits

    do
    {
        j = 8;                              // 8 bits

        do
        {
            b = ReadBit();                  // read bit
            if (ReadBit()) {                // read complement bit
                if (b) {                    // 11 = bus error
                    return eDS_DATA_ERR;    // data error
                };
            }
            else {
                if (!b) {                   // 00 = 2 devices
                    if ((_diff > i) || ((*_id & 1) && (_diff != i))) {
                        b = 1;              // now 1
                        next_diff = i;      // next pass 0
                    };
                };
            };
 
            WriteBit(b);                    // write bit
            *_id >>= 1;

            if (b) {
                *_id |= 0x80;               // store bit
            };

            i--;
        }
        while (--j);

        _id++;                              // next byte
    }
    while (i);

    return next_diff;                       // to continue search
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Run convert temperature
//==============================================================================
bool_t DS1820::ConvertTemp() {
    //  Start convert cycle
    if (MasterReset() == FALSE_T) {
        return FALSE_T;
    };
    MasterReset();

    WriteByte(eDS_SKIP_ROM);      // Skip ROM command
    WriteByte(eDS_CONVERT_TEMP);  // Convert temperature command
    return TRUE_T;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Read temp from DS18B20
//==============================================================================
bool_t DS1820::ReadTemp(sint16_t * const _pData, const uint8_t * _pUid) {
    //  Start read buff cycle
    if (MasterReset() == FALSE_T) {
        return FALSE_T;
    };
    MasterReset();

    WriteByte(eDS_MATCH_ROM);    // Match ROM command
    MultiWriteByte(_pUid, 8);

    //WriteByte(eDS_SKIP_ROM);    // Skip ROM command - singl sensor
    WriteByte(eDS_READ_TEMP);   // Read buff
    MultiReadByte(9);           // Read scratchpad data, 8 Bytes + 1 Byte CRC

    // Test CRC
    if (Crc8_Dallas(m_buff, 8) == m_buff[8]) {
        uint16_t tmp;

        (*_pData) = m_buff[1];
        (*_pData) <<= 8;
        (*_pData) |= m_buff[0];
        (*_pData) *= 50;

        // Precision for formula
        // temp = TEMP_READ - 0.25 + ((buff[7] - buff[6])/buff[7]);
        tmp = (m_buff[7] - m_buff[6]) * 100;
        tmp /= m_buff[7];
        (*_pData) -= (tmp + 25);
        return TRUE_T;
    };

    return FALSE_T;
}
//==============================================================================
//==============================================================================